Programmeringssprogsbøger forklarer, at der oprettes værdityper på stakken, og der oprettes referencetyper på bunken uden at forklare, hvad disse to ting er. Jeg har ikke læst en klar forklaring på dette. Jeg forstår, hvad en stak er. Men, Hvor og hvad er de (fysisk i en rigtig computers hukommelse)? I hvilket omfang kontrolleres de af operativsystemet eller sprogets kørselstid? Hvad er deres anvendelsesområde? Hvad bestemmer størrelsen på hver af dem? Hvad gør en hurtigere?
2020-12-07 21:37:10
Stakken er den hukommelse, der er afsat som ridseplads til en udførelsestråd. Når en funktion kaldes, reserveres en blok øverst i stakken til lokale variabler og nogle bogføringsdata. Når denne funktion vender tilbage, bliver blokken ubrugt og kan bruges næste gang en funktion kaldes. Stakken er altid reserveret i en LIFO-rækkefølge (sidst i først ud); den senest reserverede blok er altid den næste blok, der frigøres. Dette gør det virkelig nemt at holde styr på stakken; frigøre en blok fra stakken er intet andet end at justere en markør. Bunken er hukommelse afsat til dynamisk allokering. I modsætning til stakken er der ikke noget håndhævet mønster for tildeling og deallokering af blokke fra bunken; du kan tildele en blok til enhver tid og frigøre den til enhver tid. Dette gør det meget mere komplekst at holde styr på, hvilke dele af bunken der tildeles eller er gratis til enhver tid; der er mange tilpassede bunkeallokatorer til rådighed til at indstille bunkeydelse til forskellige brugsmønstre. Hver tråd får en stak, mens der typisk kun er en bunke til applikationen (selvom det ikke er ualmindeligt at have flere bunke til forskellige typer tildelinger). For at besvare dine spørgsmål direkte: I hvilket omfang styres de af OS eller sprogkørselstid? OS tildeler stakken til hver tråd på systemniveau, når tråden oprettes. Normalt kaldes operativsystemet af sprogets runtime for at tildele bunken til applikationen. Hvad er deres anvendelsesområde? Stakken er fastgjort til en tråd, så når tråden kommer ud, genvindes stakken. Bunken tildeles typisk ved opstart af applikationen af runtime og genvindes, når applikationen (teknisk proces) afsluttes. Hvad bestemmer størrelsen på hver af dem? Størrelsen på stakken indstilles, når en tråd oprettes. Størrelsen på bunken indstilles ved opstart af applikationen, men kan vokse efterhånden som der er behov for plads (tildeleren anmoder om mere hukommelse fra operativsystemet). Hvad gør en hurtigere? Stakken er hurtigere, fordi adgangsmønsteret gør det trivielt at allokere og deallokere hukommelse fra den (en pointer / heltal er simpelthen forøget eller dekrementeret), mens bunken har meget mere kompleks bogføring involveret i en allokering eller deallocation. Hver byte i stakken har også en tendens til at blive brugt meget ofte, hvilket betyder at den har tendens til at blive kortlagt til processorens cache, hvilket gør den meget hurtig. Et andet ydeevnehit for bunken er, at bunken, som for det meste er en global ressource, typisk skal være multi-threading-sikker, dvs. hver allokering og deallocation skal - typisk - synkroniseres med "alle" andre heap-adganger i programmet. En klar demonstration: Billedkilde: vikashazrati.wordpress.com | Stak: Gemt i computerens RAM ligesom bunken. Variabler, der er oprettet på stakken, kommer uden for rækkevidden og deles automatisk. Meget hurtigere at allokere i forhold til variabler på bunken. Implementeret med en faktisk stack-datastruktur. Gemmer lokale data, returadresser, der bruges til parameteroverføring. Kan have et steapeloverløb, når der bruges for meget af stakken (for det meste fra uendelig eller for dyb rekursion, meget store allokeringer). Data oprettet på stakken kan bruges uden markører. Du ville bruge stakken, hvis du ved nøjagtigt, hvor meget data du skal allokere inden kompileringstid, og den ikke er for stor. Har normalt en maksimal størrelse allerede bestemt, når dit program starter. Bunke: Gemt i computerens RAM ligesom stakken. I C ++ skal variabler på bunken ødelægges manuelt og aldrig falde uden for anvendelsesområdet. Dataene frigøres med sletning, sletning [] eller gratis. Langsommere at allokere i forhold til variabler på stakken. Anvendes efter behov til at allokere en datablok til brug af programmet. Kan have fragmentering, når der er mange tildelinger og deallokeringer. I C ++ eller C vil data oprettet på bunken blive peget på af markører og tildelt henholdsvis nye eller malloc. Kan have allokeringsfejl, hvis der anmodes om at tildeles for stor buffer. Du ville bruge bunken, hvis du ikke ved nøjagtigt, hvor meget data du har brug for på kørselstid, eller hvis du har brug for at allokere en masse data. Ansvarlig for hukommelseslækage. Eksempel: int foo () { char * pBuffer; // <- intet allokeret endnu (eksklusive selve markøren, som er tildelt her på stakken). bool b = sand; // Tildelt på stakken. hvis (b) { // Opret 500 byte på stakken char-buffer [500]; // Opret 500 byte på bunken pBuffer = ny char [500]; } // <- buffer er deallocated her, pBuffer er ikke } // <--- oops der er en hukommelseslækage, jeg skulle have kaldt delete [] pBuffer; | Det vigtigste er, at bunke og stak er generiske udtryk for måder, hvorpå hukommelse kan tildeles. De kan implementeres på mange forskellige måder, og vilkårene gælder for de grundlæggende begreber. I en stak genstande sidder genstande oven på hinanden i den rækkefølge, de blev placeret der, og du kan kun fjerne den øverste(uden at vælte det hele). Enkelheden ved en stak er, at du ikke behøver at vedligeholde en tabel, der indeholder en registrering af hver sektion af allokeret hukommelse; den eneste tilstandsinformation, du har brug for, er en enkelt markør til slutningen af stakken. For at tildele og de-allokere skal du bare forøge og mindske den enkelte markør. Bemærk: En stak kan undertiden implementeres for at starte øverst i et afsnit af hukommelsen og strække sig nedad i stedet for at vokse opad. I en bunke er der ingen særlig rækkefølge for, hvordan varer placeres. Du kan nå ind og fjerne genstande i en hvilken som helst rækkefølge, fordi der ikke er noget klart 'top' element. Heapallokering kræver opretholdelse af en fuld registrering af, hvilken hukommelse der tildeles, og hvad der ikke er, samt noget overheadvedligeholdelse for at reducere fragmentering, finde sammenhængende hukommelsessegmenter, der er store nok til at passe til den ønskede størrelse osv. Hukommelse kan tildeles på et hvilket som helst tidspunkt, hvilket giver ledig plads. Nogle gange udfører en hukommelsesalloker vedligeholdelsesopgaver såsom at defragmentere hukommelsen ved at flytte den allokerede hukommelse rundt eller indsamle affald - identificere ved kørsel, når hukommelsen ikke længere er i rækkevidde og omfordele den. Disse billeder skal gøre et ret godt stykke arbejde med at beskrive de to måder at allokere og frigøre hukommelse i en stak og en bunke. Yum! I hvilket omfang styres de af OS eller sprogkørselstid? Som nævnt er heap og stack generelle vilkår og kan implementeres på mange måder. Computerprogrammer har typisk en stak kaldet en opkaldsstak, der gemmer information, der er relevant for den aktuelle funktion, såsom en markør til hvilken funktion den blev kaldt fra, og eventuelle lokale variabler. Da funktioner kalder på andre funktioner og derefter vender tilbage, vokser stakken og krymper for at holde information fra funktionerne længere nede i opkaldsstakken. Et program har ikke rigtig runtime kontrol over det; det bestemmes af programmeringssproget, OS og endda systemarkitekturen. En bunke er en generel betegnelse, der bruges til enhver hukommelse, der tildeles dynamisk og tilfældigt; dvs. ude af drift. Hukommelsen tildeles typisk af operativsystemet, hvor applikationen kalder API-funktioner til at foretage denne allokering. Der kræves en hel del overhead til styring af dynamisk allokeret hukommelse, som normalt håndteres af runtime-koden for det anvendte programmeringssprog eller miljø. Hvad er deres anvendelsesområde? Opkaldstakken er et så lavt koncept, at det ikke relaterer til 'omfang' i form af programmering. Hvis du adskiller en eller anden kode, kan du se referencer til relative markørstil til dele af stakken, men for så vidt angår et højere sprog, pålægger sproget sine egne regler for anvendelsesområdet. Et vigtigt aspekt af en stak er dog, at når en funktion er tilbage, frigøres alt, hvad der er lokalt for den funktion, straks fra stakken. Det fungerer som du ville forvente, at det skulle fungere i betragtning af hvordan dine programmeringssprog fungerer. I en bunke er det også svært at definere. Omfanget er uanset hvad der udsættes for operativsystemet, men dit programmeringssprog tilføjer sandsynligvis sine regler om, hvad et "omfang" er i din applikation. Processorarkitekturen og operativsystemet bruger virtuel adressering, som processoren oversætter til fysiske adresser, og der er sidefejl osv. De holder styr på, hvilke sider der hører til hvilke applikationer. Du behøver aldrig rigtig bekymre dig om dette, for du bruger bare den metode, dit programmeringssprog bruger til at allokere og frigøre hukommelse og kontrollere for fejl (hvis tildelingen / frigørelsen mislykkes af en eller anden grund). Hvad bestemmer størrelsen på hver af dem? Igen afhænger det af sprog, kompilator, operativsystem og arkitektur. En stak er normalt forudallokeret, fordi den per definition skal være sammenhængende hukommelse. Sprogkompilatoren eller operativsystemet bestemmer størrelsen. Du gemmer ikke store klumper af data på stakken, så det vil være stort nok til, at det aldrig skal bruges fuldt ud, undtagen i tilfælde af uønsket endeløs rekursion (dermed "stack overflow") eller andre usædvanlige programmeringsbeslutninger. En bunke er en generel betegnelse for alt, hvad der kan tildeles dynamisk. Afhængigt af hvilken måde du ser på det, ændrer det konstant størrelse. I moderne processorer og operativsystemer er den nøjagtige måde, det fungerer på, alligevel meget abstrakt, så du behøver normalt ikke bekymre dig meget om, hvordan det fungerer dybt nede, bortset fra at (på sprog, hvor det giver dig mulighed) du ikke må bruge hukommelse, der du ikke har tildelt endnu eller hukommelse, som du har frigivet. Hvad gør en hurtigere? Stakken er hurtigere, fordi al ledig hukommelse altid er sammenhængende. Ingen liste behøver at blive vedligeholdt over alle segmenterne af fri hukommelse, kun en enkelt markør til den aktuelle top af stakken. Kompilatorer gemmer normalt denne markør i et specielt, hurtigt register til dette formål. Hvad mere er, efterfølgende operationer på en stak er normalt koncentreret inden for meget nærliggende hukommelsesområder, hvilket på et meget lavt niveau er godt til optimering af processoren på-diecacher. | (Jeg har flyttet dette svar fra et andet spørgsmål, der mere eller mindre var en bedragere af dette.) Svaret på dit spørgsmål er implementeringsspecifikt og kan variere på tværs af kompilatorer og processorarkitekturer. Her er dog en forenklet forklaring. Både stakken og bunken er hukommelsesområder, der er allokeret fra det underliggende operativsystem (ofte virtuel hukommelse, der kortlægges til fysisk hukommelse efter behov). I et miljø med flere tråde har hver tråd sin egen helt uafhængige stak, men de deler bunken. Samtidig adgang skal kontrolleres på bunken og er ikke mulig på stakken. Bunken Bunken indeholder en sammenkædet liste over brugte og gratis blokke. Nye tildelinger på bunken (af ny eller malloc) opfyldes ved at oprette en passende blok fra en af de gratis blokke. Dette kræver opdatering af listen over blokke på bunken. Disse metaoplysninger om blokke på bunken lagres også på bunken ofte i et lille område lige foran hver blok. Efterhånden som dyngen vokser, tildeles nye blokke ofte fra lavere adresser til højere adresser. Således kan du tænke på bunken som en bunke med hukommelsesblokke, der vokser i størrelse, når hukommelsen tildeles. Hvis bunken er for lille til en allokering, kan størrelsen ofte øges ved at erhverve mere hukommelse fra det underliggende operativsystem. Tildeling og deallokering af mange små blokke kan efterlade bunken i en tilstand, hvor der er en masse små gratis blokke, der er afbrudt mellem de brugte blokke. En anmodning om at tildele en stor blok kan mislykkes, fordi ingen af de gratis blokke er store nok til at tilfredsstille allokeringsanmodningen, selvom den samlede størrelse af de gratis blokke kan være stor nok. Dette kaldes bunkefragmentering. Når en brugt blok, der støder op til en fri blok, omplaceres, kan den nye frie blok flettes med den tilstødende frie blok for at skabe en større fri blok, der effektivt reducerer fragmenteringen af bunken. Stakken Stakken fungerer ofte tæt sammen med et specielt register på CPU'en, der hedder stakemarkøren. Oprindeligt peger stakmarkøren til toppen af stakken (den højeste adresse på stakken). CPU'en har specielle instruktioner til at skubbe værdier på stakken og springe dem tilbage fra stakken. Hvert skub gemmer værdien på den aktuelle placering af stakemarkøren og formindsker stakmarkøren. En pop henter den værdi, som stakemarkøren peger på, og øger derefter stakemarkøren (bliv ikke forvirret af det faktum, at tilføjelse af en værdi til stakken reducerer stakmarkøren og fjernelse af en værdi øger den. Husk, at stakken vokser til bunden). Værdierne, der er gemt og hentet, er værdierne i CPU-registrene. Når en funktion kaldes, bruger CPU specielle instruktioner, der skubber den aktuelle instruktionsmarkør, dvs. adressen på den kode, der udføres på stakken. CPU'en hopper derefter til funktionen ved at indstille instruktionsmarkør til adressen på den kaldte funktion. Senere, når funktionen vender tilbage, poppes den gamle instruktionsmarkør fra stakken, og udførelsen genoptages ved koden lige efter opkaldet til funktionen. Når en funktion indtastes, reduceres stakemarkøren for at tildele mere plads på stakken til lokale (automatiske) variabler. Hvis funktionen har en lokal 32 bit variabel, er der afsat fire byte på stakken. Når funktionen vender tilbage, flyttes stakemarkøren tilbage for at frigøre det tildelte område. Hvis en funktion har parametre, skubbes disse på stakken inden opkaldet til funktionen. Koden i funktionen er så i stand til at navigere op ad stakken fra den aktuelle stakemarkør for at finde disse værdier. Indlejringsfunktionsopkald fungerer som en charme. Hvert nyt opkald tildeler funktionsparametre, returadresse og plads til lokale variabler, og disse aktiveringsposter kan stables til indlejrede opkald og vil slappe af på den rigtige måde, når funktionerne vender tilbage. Da stakken er en begrænset hukommelsesblok, kan du forårsage en stackoverløb ved at kalde for mange indlejrede funktioner og / eller tildele for meget plads til lokale variabler. Ofte er hukommelsesområdet, der bruges til stakken, indstillet på en sådan måde, at skrivning under bunden (den laveste adresse) på stakken vil udløse en fælde eller undtagelse i CPU'en. Denne ekstraordinære tilstand kan derefter fanges af runtime og konverteres til en slags undtagelse fra stackoverløb. Kan en funktion tildeles på bunken i stedet for en stak? Nej, aktiveringsregistreringer for funktioner (dvs. lokale eller automatiske variabler) tildeles på stakken, der ikke kun bruges til at gemme disse variabler, men også til at holde styr på indlejrede funktionsopkald. Sådan styres bunken er virkelig op til runtime-miljøet. C bruger malloc og C ++ bruger nyt, men mange andre sprog har affaldssamling. Stakken er dog en mere lavt niveau-funktion tæt knyttet til processorarkitekturen. At dyrke bunken, når der ikke er nok plads, er ikke så svært sidendet kan implementeres i biblioteksopkaldet, der håndterer bunken. Det er dog ofte umuligt at dyrke stakken, da stackoverløb først opdages, når det er for sent; og at lukke henrettelsestråden er den eneste mulige mulighed. | I den følgende C # kode offentlig ugyldig Metode1 () { int i = 4; int y = 2; klasse1 cls1 = ny klasse1 (); } Sådan styres hukommelsen Lokale variabler, der kun behøver at vare, så længe funktionsopkaldet går i stakken. Bunken bruges til variabler, hvis levetid vi ikke rigtig kender foran, men vi forventer, at de varer et stykke tid. På de fleste sprog er det vigtigt, at vi ved kompileringstidspunktet ved, hvor stor en variabel er, hvis vi vil gemme den på stakken. Objekter (som varierer i størrelse, når vi opdaterer dem) går på bunken, fordi vi ikke ved oprettelsestidspunktet, hvor længe de skal vare. På mange sprog samles bunken skrald for at finde objekter (såsom cls1-objektet), der ikke længere har nogen referencer. I Java går de fleste objekter direkte ind i bunken. På sprog som C / C ++ kan strukturer og klasser ofte forblive på stakken, når du ikke har at gøre med markører. Flere oplysninger kan findes her: Forskellen mellem tildeling af stack og heaphukommelse «timmurphy.org og her: Oprettelse af objekter på stakken og bunken Denne artikel er kilden til billedet ovenfor: Seks vigtige .NET-koncepter: Stak, heap, værdityper, referencetyper, boksning og unboxing - CodeProject men vær opmærksom på, at det kan indeholde nogle unøjagtigheder. | Stakken Når du kalder en funktion, lægges argumenterne for den funktion plus nogle andre omkostninger på stakken. Noget info (f.eks. Hvor man skal hen ved retur) gemmes også der. Når du erklærer en variabel inde i din funktion, tildeles den variabel også på stakken. At omfordele stakken er ret simpelt, fordi du altid deallokerer i den omvendte rækkefølge, som du tildeler. Stakemner tilføjes, når du indtaster funktioner, de tilsvarende data fjernes, når du afslutter dem. Dette betyder, at du har en tendens til at forblive inden for et lille område af stakken, medmindre du kalder på mange funktioner, der kalder mange andre funktioner (eller opretter en rekursiv løsning). Bunken Bunken er et generisk navn til, hvor du placerer de data, du opretter, i farten. Hvis du ikke ved, hvor mange rumskibe dit program vil oprette, vil du sandsynligvis bruge den nye (eller malloc eller tilsvarende) operatør til at oprette hvert rumskib. Denne tildeling vil holde fast i et stykke tid, så det er sandsynligt, at vi vil frigøre ting i en anden rækkefølge, end vi oprettede dem. Således er bunken langt mere kompleks, fordi der ender med at være hukommelsesregioner, der er ubrugt sammenflettet med klumper, der er - hukommelsen bliver fragmenteret. At finde ledig hukommelse i den størrelse, du har brug for, er et vanskeligt problem. Dette er grunden til, at bunken skal undgås (selvom den stadig bruges ofte). Implementering Implementering af både stakken og bunken er normalt ned til runtime / OS. Ofte skaber spil og andre applikationer, der er ydeevnekritiske, deres egne hukommelsesløsninger, der tager et stort stykke hukommelse fra bunken og derefter skiller det ud internt for at undgå at stole på operativsystemet til hukommelse. Dette er kun praktisk, hvis dit hukommelsesforbrug er helt forskelligt fra normen - dvs. for spil, hvor du indlæser et niveau i en enorm operation og kan chuck det hele i en anden enorm operation. Fysisk placering i hukommelsen Dette er mindre relevant, end du tror på grund af en teknologi kaldet Virtual Memory, der får dit program til at tro, at du har adgang til en bestemt adresse, hvor de fysiske data er et andet sted (selv på harddisken!). Adresserne, du får til stakken, er i stigende rækkefølge, når dit opkaldstræ bliver dybere. Adresserne til bunken er uforudsigelige (dvs. implimenteringsspecifikke) og ærligt talt ikke vigtige. | For at afklare, har dette svar forkerte oplysninger (thomas fik sit svar efter kommentarer, sejt :)). Andre svar undgår bare at forklare, hvad statisk tildeling betyder. Så jeg vil forklare de tre vigtigste tildelingsformer, og hvordan de normalt relaterer til bunke-, stak- og datasegmentet nedenfor. Jeg vil også vise nogle eksempler i både C / C ++ og Python for at hjælpe folk med at forstå. "Statiske" (AKA statisk tildelte) variabler tildeles ikke på stakken. Antag ikke det - mange mennesker gør kun fordi "statisk" lyder meget som "stak". De eksisterer faktisk hverken i stakken eller bunken. De er en del af det, der kaldes datasegmentet. Det er dog generelt bedre at overveje "omfang" og "levetid" snarere end "stak" og "bunke". Omfang henviser til, hvilke dele af koden der kan få adgang til en variabel. Generelt tænker vi på lokalt omfang (kan kun fås med den aktuelle funktion) versus globalt omfang (kan fås overalt), selvom omfanget kan blive meget mere komplekst. Lifetime henviser til, hvornår en variabel tildeles og deallokeres under programudførelse. Normalt tænker vi på statisk tildeling (variabelfortsætter gennem hele programvarigheden, hvilket gør det nyttigt til lagring af de samme oplysninger på tværs af flere funktionsopkald) versus automatisk tildeling (variabel fortsætter kun under et enkelt opkald til en funktion, hvilket gør den nyttig til lagring af information, der kun bruges under funktion og kan kasseres, når du er færdig) versus dynamisk fordeling (variabler, hvis varighed er defineret ved kørsel, i stedet for kompileringstid som statisk eller automatisk). Selvom de fleste compilere og tolke implementerer denne adfærd på samme måde med hensyn til brug af stakke, dynger osv., Kan en kompilator undertiden bryde disse konventioner, hvis den ønsker, så længe adfærd er korrekt. For eksempel kan en lokal variabel muligvis kun eksistere i et register eller fjernes helt på grund af optimering, selvom de fleste lokale variabler findes i stakken. Som det er blevet påpeget i nogle få kommentarer, er du fri til at implementere en compiler, der ikke engang bruger en stak eller en bunke, men i stedet nogle andre lagringsmekanismer (sjældent gjort, da stakke og bunker er gode til dette). Jeg vil give nogle enkle kommenterede C-koder for at illustrere alt dette. Den bedste måde at lære er at køre et program under en debugger og se adfærd. Hvis du foretrækker at læse python, skal du springe til slutningen af svaret :) // Statisk tildelt i datasegmentet, når programmet / DLL'en først indlæses // Deallocated når programmet / DLL afsluttes // scope - kan tilgås hvor som helst i koden int nogleGlobalVariable; // Statisk tildelt i datasegmentet, når programmet først indlæses // Deallocated når programmet / DLL afsluttes // scope - kan tilgås hvor som helst i denne bestemte kodefil statisk int someStaticVariable; // "someArgument" tildeles på stakken hver gang MyFunction kaldes // "someArgument" deallocated når MyFunction vender tilbage // scope - kan kun fås inden for MyFunction () ugyldig MyFunction (int someArgument) { // Statisk tildelt i datasegmentet, når programmet først indlæses // Deallocated når programmet / DLL afsluttes // scope - kan kun fås inden for MyFunction () statisk int someLocalStaticVariable; // Tildelt på stakken hver gang MyFunction kaldes // Deallocated når MyFunction vender tilbage // scope - kan kun fås inden for MyFunction () int someLocalVariable; // En * markør * tildeles på stakken hver gang MyFunction kaldes // Denne markør deles, når MyFunction vender tilbage // scope - markøren er kun tilgængelig i MyFunction () int * someDynamicVariable; // Denne linje får plads til et heltal, der tildeles i bunken // når denne linje udføres. Bemærk dette er ikke i begyndelsen af // opkaldet til MyFunction (), ligesom de automatiske variabler // scope - kun kode inden for MyFunction () har adgang til dette rum // * gennem denne særlige variabel *. // Hvis du imidlertid sender adressen et andet sted, skal den kode // kan også få adgang til det someDynamicVariable = ny int; // Denne linje deallokerer pladsen til heltal i bunken. // Hvis vi ikke skrev det, ville hukommelsen blive "lækket". // Bemærk en grundlæggende forskel mellem stakken og bunken // bunken skal styres. Stakken styres for os. slet nogetDynamicVariable; // I andre tilfælde, i stedet for at deallocere denne bunke plads dig // kan gemme adressen et eller andet sted mere permanent til senere brug. // Nogle sprog tager endda sig af deallocation for dig ... men // det skal altid tages hånd om ved kørsel af en eller anden mekanisme. // Når funktionen vender tilbage, someArgument, someLocalVariable // og markøren someDynamicVariable er deallocated. // Rummet, som nogleDynamicVariable pegede på, var allerede // deallocated før retur. Vend tilbage; } // Bemærk, at nogleGlobalVariable, someStaticVariable og // someLocalStaticVariable eksisterer fortsat og er ikke // deallocated indtil programmet afsluttes. Et særligt gribende eksempel på, hvorfor det er vigtigt at skelne mellem levetid og omfang, er at en variabel kan have lokalt omfang, men statisk levetid - for eksempel "someLocalStaticVariable" i kodeeksemplet ovenfor. Sådanne variabler kan gøre vores almindelige, men uformelle navngivningsvaner meget forvirrende. For eksempel når vi siger "lokal" mener vi normalt "automatisk tildelt variabel med lokal rækkevidde", og når vi siger global, mener vi normalt "statisk allokeret variabel med globalt omfang". Desværre når det kommer til ting som "filomfanget statisk tildelte variabler" siger mange mennesker bare ... "he ???". Nogle af syntaksvalgene i C / C ++ forværrer dette problem - for eksempel tror mange mennesker, at globale variabler ikke er "statiske" på grund af syntaksen vist nedenfor. int var1; // Har globalt omfang og statisk tildeling statisk int var2; // Har filomfang og statisk tildeling int main () {return 0;} Bemærk, at placeringen af nøgleordet "statisk" i erklæringen ovenfor forhindrer var2 i at have globalt omfang. Ikke desto mindre har den globale var1 statisk tildeling. Dette er ikkeintuitiv! Af denne grund forsøger jeg aldrig at bruge ordet "statisk", når jeg beskriver omfang, og i stedet sige noget som "fil" eller "filbegrænset" omfang. Imidlertid bruger mange udtrykket "statisk" eller "statisk rækkevidde" til at beskrive en variabel, der kun kan tilgås fra en kodefil. I sammenhæng med levetid betyder "statisk" altid, at variablen tildeles ved programstart og deallokeres, når programmet afsluttes. Nogle mennesker tænker på disse begreber som C / C ++ specifikke. De er ikke. For eksempel illustrerer Python-eksemplet nedenfor alle tre typer tildeling (der er nogle subtile forskelle i fortolkede sprog, som jeg ikke kommer ind på her). fra datetime import datetime klasse Dyr: _FavoriteFood = 'Udefineret' # _FavoriteFood tildeles statisk def PetAnimal (selv): curTime = datetime.time (datetime.now ()) # curTime tildeles automatisk udskriv ("Tak fordi du har klappet mig. Men det er" + str (curTime) + ", du skal fodre mig. Min yndlings mad er" + self._FavoriteFood) klasse Kat (dyr): _FavoriteFood = 'tun' # Bemærk da vi tilsidesætter, har Cat-klassen sin egen statisk tildelte _FavoriteFood-variabel, forskellig fra dyrets klasse Hund (dyr): _FavoriteFood = 'bøf' # Ligeledes får hundeklassen sin egen statiske variabel. Vigtigt at bemærke - denne ene statiske variabel deles mellem alle forekomster af hund, derfor er den ikke dynamisk! hvis __name__ == "__main__": whiskers = Cat () # Dynamisk tildelt fido = Hund () # Dynamisk tildelt rinTinTin = Hund () # Dynamisk tildelt whiskers.PetAnimal () fido.PetAnimal () rinTinTin.PetAnimal () Dog._FavoriteFood = 'mælkeknogler' whiskers.PetAnimal () fido.PetAnimal () rinTinTin.PetAnimal () # Output er: # Tak fordi du har klappet mig. Men det er 13: 05: 02.255000, du skal give mig mad. Min yndlings mad er tun # Tak fordi du har klappet mig. Men det er 13: 05: 02.255000, du skal give mig mad. Min yndlings mad er bøf # Tak fordi du har klappet mig. Men det er 13: 05: 02.255000, du skal give mig mad. Min yndlings mad er bøf # Tak fordi du har klappet mig. Men det er 13: 05: 02.255000, du skal give mig mad. Min yndlings mad er tun # Tak fordi du har klappet mig. Men det er 13: 05: 02.255000, du skal give mig mad. Min yndlings mad er mælkeben # Tak fordi du har klappet mig. Men det er 13: 05: 02.256000, du skal give mig mad. Min yndlings mad er mælkeben | Andre har svaret de brede streger ret godt, så jeg smider et par detaljer ind. Stak og bunke behøver ikke at være ental. En almindelig situation, hvor du har mere end en stak, er, hvis du har mere end en tråd i en proces. I dette tilfælde har hver tråd sin egen stak. Du kan også have mere end en bunke, for eksempel kan nogle DLL-konfigurationer resultere i forskellige DLL'er, der tildeles fra forskellige bunker, hvorfor det generelt er en dårlig ide at frigive hukommelse allokeret af et andet bibliotek. I C kan du få fordelen ved allokering med variabel længde ved brug af alloca, som tildeles på stakken, i modsætning til allokering, som tildeles på bunken. Denne hukommelse overlever ikke din returerklæring, men den er nyttig til en ridsebuffer. At lave en enorm midlertidig buffer på Windows, som du ikke bruger meget af, er ikke gratis. Dette skyldes, at kompilatoren vil generere en stakksonde-løkke, der kaldes til, hver gang din funktion indtastes for at sikre, at stakken eksisterer (fordi Windows bruger en enkelt beskyttelsesside i slutningen af din stak til at opdage, hvornår den skal vokse stakken. Hvis du får adgang til hukommelse mere end en side fra slutningen af stakken, vil du gå ned). Eksempel: ugyldig min funktion () { char stor [10000000]; // Gør noget, der kun bruger de første 1K af store 99% af tiden. } | Andre har svaret direkte på dit spørgsmål, men når jeg prøver at forstå stakken og bunken, synes jeg det er nyttigt at overveje hukommelseslayoutet for en traditionel UNIX-proces (uden tråde og mmap () -baserede allokatorer). Webstedet Memory Management Glossary har et diagram over dette hukommelseslayout. Stakken og bunken er traditionelt placeret i modsatte ender af processens virtuelle adresseområde. Stakken vokser automatisk, når den åbnes, op til en størrelse, der er indstillet af kernen (som kan justeres med setrlimit (RLIMIT_STACK, ...)). Bunken vokser, når hukommelsesallokereren påkalder systemkaldet brk () eller sbrk () og kortlægger flere sider med fysisk hukommelse i processens virtuelle adresseområde. I systemer uden virtuel hukommelse, såsom nogle indlejrede systemer, gælder det samme grundlæggende layout ofte, bortset fra at stakken og bunken er fast i størrelse. I andre indlejrede systemer (såsom dem, der er baseret på Microchip PIC-mikrocontrollere), er programstakken en separat hukommelsesblok, der ikke kan adresseres af instruktioner til dataflytning og kun kan ændres eller læses indirekte gennem programflowinstruktioner (kald retur osv.). Andre arkitekturer, såsom Intel Itanium-processorer, har flere stakke. I denne forstand er stakken et element i CPU-arkitekturen. | Stakken er en delhukommelse, der kan manipuleres via flere nøglesamlingssproginstruktioner, såsom 'pop' (fjern og returner en værdi fra stakken) og 'push' (skub en værdi til stakken), men også kald (kald en underrutine - dette skubber adressen for at vende tilbage til stakken) og returnere (vende tilbage fra en underrutine - dette springer adressen ud af stakken og springer til den). Det er hukommelsesområdet under stakpointerregistret, som kan indstilles efter behov. Stakken bruges også til at videregive argumenter til underrutiner og også til at bevare værdierne i registre, før der kaldes til underrutiner. Bunken er en del af hukommelsen, der gives til en applikation af operativsystemet, typisk gennem en syscall som malloc. På moderne operativsystemer er denne hukommelse et sæt sider, som kun opkaldsprocessen har adgang til. Stakkens størrelse bestemmes ved kørselstid og vokser generelt ikke, når programmet startes. I et C-program skal stakken være stor nok til at indeholde hver variabel, der er deklareret inden for hver funktion. Bunken vil vokse dynamisk efter behov, men operativsystemet foretager i sidste ende opkaldet (det vil ofte vokse bunken med mere end den værdi, der kræves af malloc, så i det mindste nogle fremtidige mallocs ikke behøver at gå tilbage til kernen til få mere hukommelse. Denne adfærd kan ofte tilpasses) Fordi du har tildelt stakken, før du starter programmet, behøver du aldrig malloc, før du kan bruge stakken, så det er en lille fordel der. I praksis er det meget svært at forudsige, hvad der vil være hurtigt, og hvad der vil være langsomt i moderne operativsystemer, der har virtuelle hukommelsessystemer, for hvordan siderne implementeres, og hvor de er gemt, er en implementeringsdetalje. | Hvad er en stak? En stak er en bunke med objekter, typisk en, der er pænt arrangeret. Stakke i computerarkitekturer er hukommelsesregioner, hvor data tilføjes eller fjernes på en sidste-i-første-ud-måde. I en applikation med flere tråde har hver tråd sin egen stak. Hvad er en bunke? En bunke er en rodet samling af ting, der er stablet tilfældigt. I computerarkitekturer er bunken et område med dynamisk allokeret hukommelse, der administreres automatisk af operativsystemet eller hukommelsesadministratorbiblioteket. Hukommelse på bunken allokeres, dealloceres og ændres størrelsen regelmæssigt under programudførelse, og dette kan føre til et problem kaldet fragmentering. Fragmentering opstår, når hukommelsesobjekter tildeles med små mellemrum imellem, der er for små til at rumme yderligere hukommelsesobjekter. Nettoresultatet er en procentdel af bunkerummet, der ikke kan bruges til yderligere hukommelsesallokeringer. Begge sammen I en applikation med flere tråde har hver tråd sin egen stak. Men alle de forskellige tråde deler bunken. Fordi de forskellige tråde deler bunken i en applikation med flere tråde, betyder det også, at der skal være en vis koordinering mellem tråde, så de ikke forsøger at få adgang til og manipulere det samme stykke hukommelse i bunken kl. den samme tid. Hvilket er hurtigere - stakken eller bunken? Og hvorfor? Stakken er meget hurtigere end bunken. Dette skyldes den måde, hvorpå hukommelsen tildeles på stakken. Tildeling af hukommelse på stakken er så simpelt som at flytte stakmarkøren op. For folk, der er nye med programmering, er det sandsynligvis en god ide at bruge stakken, da den er lettere. Da stakken er lille, vil du gerne bruge den, når du ved nøjagtigt, hvor meget hukommelse du har brug for til dine data, eller hvis du ved, at størrelsen på dine data er meget lille. Det er bedre at bruge bunken, når du ved, at du har brug for meget hukommelse til dine data, eller hvis du bare ikke er sikker på, hvor meget hukommelse du har brug for (som med et dynamisk array). Java-hukommelsesmodel Stakken er det hukommelsesområde, hvor lokale variabler (inklusive metodeparametre) er gemt. Når det kommer til objektvariabler, er det kun referencer (pointer) til de faktiske objekter på bunken. Hver gang et objekt instantieres, afsættes et stykke bunkehukommelse til at holde dataene (tilstanden) for det objekt. Da objekter kan indeholde andre objekter, kan nogle af disse data faktisk indeholde referencer til de indlejrede objekter. | Jeg tror, at mange andre mennesker for det meste har givet dig korrekte svar. En detalje, der er gået glip af, er imidlertid, at "bunken" faktisk sandsynligvis skal kaldes "gratis butik". Årsagen til denne sondring er, at den originale gratis butik blev implementeret med en datastruktur kendt som en "binomial bunke." Af den grund var tildeling fra tidlige implementeringer af malloc () / free () tildeling fra en bunke. Men i denne moderne tid implementeres de fleste gratis butikker med meget detaljerede datastrukturer, der ikke er binomale dynger. | Du kan gøre nogle interessante ting med stakken. For eksempel har du funktioner som alloca (forudsat at du kan komme forbi de rigelige advarsler om brugen), hvilket er en form for malloc, derbruger specifikt stakken, ikke bunken, til hukommelse. Når det er sagt, er stack-baserede hukommelsesfejl nogle af de værste, jeg har oplevet. Hvis du bruger hukommelseshukommelse, og du overskrider grænserne for din tildelte blok, har du en anstændig chance for at udløse en segmentfejl. (Ikke 100%: din blok kan i øvrigt være sammenhængende med en anden, som du tidligere har tildelt.) Men da variabler oprettet på stakken altid er sammenhængende med hinanden, kan udskrivning uden for grænser ændre værdien af en anden variabel. Jeg har lært, at når jeg føler, at mit program er stoppet med at overholde logikkens love, er det sandsynligvis bufferoverløb. | Simpelthen er stakken, hvor lokale variabler oprettes. Hver gang du kalder en underrutine, vises også programtælleren (markør til næste maskineinstruktion) og vigtige registre, og nogle gange bliver parametrene skubbet på stakken. Derefter skubbes eventuelle lokale variabler inde i subrutinen på stakken (og bruges derfra). Når subrutinen er færdig, springer de ting alle tilbage fra stakken. PC- og registerdataene kommer og lægges tilbage, hvor de var, som de blev poppet, så dit program kan fortsætte sin glade vej. Bunken er området for hukommelse, dynamiske hukommelsestildelinger er lavet af (eksplicit "nye" eller "tildel" opkald). Det er en speciel datastruktur, der kan holde styr på hukommelsesblokke i forskellige størrelser og deres allokeringsstatus. I "klassiske" systemer blev RAM lagt sådan, at stakemarkøren startede i bunden af hukommelsen, bunkemarkøren startede øverst, og de voksede mod hinanden. Hvis de overlapper hinanden, har du ikke mere RAM. Det fungerer dog ikke med moderne operativsystemer med flere tråde. Hver tråd skal have sin egen stak, og de kan oprettes dynamisk. | Fra WikiAnwser. Stak Når en funktion eller en metode kalder en anden funktion, som igen kalder en anden funktion osv., Forbliver udførelsen af alle disse funktioner suspenderet, indtil den sidste funktion returnerer sin værdi. Denne kæde af suspenderede funktionsopkald er stakken, fordi elementer i stakken (funktionsopkald) afhænger af hinanden. Stakken er vigtig at overveje i undtagelseshåndtering og trådudførelser. Bunke Bunken er simpelthen den hukommelse, der bruges af programmer til at gemme variabler. Element af bunken (variabler) har ingen afhængigheder med hinanden og kan altid tilgås tilfældigt når som helst. | Stak Meget hurtig adgang Behøver ikke eksplicit at allokere variabler Plads styres effektivt af CPU, hukommelse bliver ikke fragmenteret Kun lokale variabler Begrænsning af stakstørrelse (OS-afhængig) Variabler kan ikke ændres Bunke Variabler er tilgængelige globalt Ingen grænse for hukommelsesstørrelse (Relativt) langsommere adgang Ingen garanteret effektiv brug af plads, hukommelse kan blive fragmenteret over tid, når hukommelsesblokke allokeres og derefter frigøres Du skal administrere hukommelse (du har ansvaret for tildeling og frigørelse af variabler) Variabler kan ændres ved hjælp af realloc () | Kort sagt En stak bruges til statisk hukommelsesallokering og en bunke til dynamisk hukommelsesallokering, begge gemt i computerens RAM. I detaljer Stakken Stakken er en "LIFO" (sidste ind, først ud) datastruktur, der styres og optimeres af CPU'en ret tæt. Hver gang en funktion erklærer en ny variabel, skubbes den på stakken. Derefter frigøres alle variabler, der skubbes på stakken af denne funktion, hver gang en funktion afsluttes (det vil sige de slettes). Når en stabelvariabel er frigjort, bliver denne hukommelsesregion tilgængelig for andre stakvariabler. Fordelen ved at bruge stakken til at gemme variabler er, at hukommelsen styres for dig. Du behøver ikke at allokere hukommelse i hånden eller frigøre den, når du ikke mere har brug for den. Hvad mere er, fordi CPU'en organiserer stackhukommelse så effektivt, er det meget hurtigt at læse fra og skrive til stack-variabler. Mere kan findes her. Bunken Bunken er en region i din computers hukommelse, der ikke administreres automatisk for dig og ikke styres så tæt af CPU'en. Det er en mere fritflydende hukommelsesregion (og er større). For at tildele hukommelse på bunken skal du bruge malloc () eller calloc (), som er indbyggede C-funktioner. Når du har tildelt hukommelse på bunken, er du ansvarlig for at bruge gratis () til at omfordele hukommelsen, når du ikke har brug for det mere. Hvis du ikke gør dette, vil dit program have det, der kaldes en hukommelseslækage. Det vil sige, hukommelse på bunken vil stadig blive afsat (og vil ikke være tilgængelig for andre processer). Som vi vil se i fejlfindingsafsnittet, er der et værktøj kaldet Valgrind, der kan hjælpe dig med at opdage hukommelseslækager. I modsætning til stakken har bunken ikke størrelsesbegrænsninger for variabel størrelse (bortset fra de åbenlyse fysiske begrænsninger på din computer). Bunkehukommelse er lidt langsommere at læse fra og skrive til, fordi man skal bruge pegepinde for at få adgang til hukommelse på bunken. Vi vil snakke om henvisninger inden længe. I modsætning til stakken,variabler oprettet på bunken er tilgængelige for enhver funktion, hvor som helst i dit program. Heapvariabler er i det væsentlige globale i omfang. Mere kan findes her. Variabler, der er allokeret på stakken, lagres direkte i hukommelsen, og adgangen til denne hukommelse er meget hurtig, og dens allokering behandles, når programmet kompileres. Når en funktion eller en metode kalder en anden funktion, som igen kalder en anden funktion osv., Forbliver udførelsen af alle disse funktioner suspenderet, indtil den sidste funktion returnerer sin værdi. Stakken er altid reserveret i en LIFO-rækkefølge, den senest reserverede blok er altid den næste blok, der frigøres. Dette gør det virkelig nemt at holde styr på stakken, det er intet andet end at justere en markør at frigøre en blok fra stakken. Variabler, der er allokeret på bunken, har deres hukommelse allokeret ved kørselstid, og adgang til denne hukommelse er lidt langsommere, men bunkestørrelsen er kun begrænset af størrelsen på den virtuelle hukommelse. Elementer af bunken har ingen afhængigheder med hinanden og kan altid tilgås tilfældigt når som helst. Du kan tildele en blok til enhver tid og frigøre den til enhver tid. Dette gør det meget mere komplekst at holde styr på, hvilke dele af bunken der er tildelt eller gratis til enhver tid. Du kan bruge stakken, hvis du ved nøjagtigt, hvor meget data du skal allokere inden kompileringstid, og den ikke er for stor. Du kan bruge bunken, hvis du ikke ved nøjagtigt, hvor meget data du har brug for under kørsel, eller hvis du har brug for at allokere en masse data. I en situation med flere tråde har hver tråd sin egen helt uafhængige stak, men de deler bunken. Stakken er trådspecifik og bunken er applikationsspecifik. Stakken er vigtig at overveje i undtagelseshåndtering og trådudførelser. Hver tråd får en stak, mens der typisk kun er en bunke til applikationen (selvom det ikke er ualmindeligt at have flere bunke til forskellige typer tildelinger). Hvis applikationen har brug for mere heap ved kørsel, kan den allokere hukommelse fra ledig hukommelse, og hvis stakken har brug for hukommelse, kan den allokere hukommelse fra ledig hukommelsesallokeret hukommelse til applikationen. Endnu flere detaljer gives her og her. Kom nu til dit spørgsmåls svar. I hvilket omfang styres de af OS eller sprogkørselstid? OS tildeler stakken til hver tråd på systemniveau, når tråden oprettes. Normalt kaldes operativsystemet af sprogets runtime for at tildele bunken til applikationen. Mere kan findes her. Hvad er deres anvendelsesområde? Allerede givet i toppen. "Du kan bruge stakken, hvis du ved nøjagtigt, hvor meget data du skal allokere inden kompileringstid, og den ikke er for stor. Du kan bruge bunken, hvis du ikke ved nøjagtigt, hvor meget data du har brug for ved kørsel, eller hvis du er nødt til at allokere en masse data. " Mere kan findes her. Hvad bestemmer størrelsen på hver af dem? Størrelsen på stakken indstilles af OS, når en tråd oprettes. Størrelsen på bunken indstilles ved opstart af applikationen, men den kan vokse, når der er behov for plads (tildeleren anmoder om mere hukommelse fra operativsystemet). Hvad gør en hurtigere? Stableallokering er meget hurtigere, da alt det virkelig gør er at flytte stakemarkøren. Ved hjælp af hukommelsespuljer kan du få sammenlignelig ydelse ud af bunktildeling, men det kommer med en let ekstra kompleksitet og dens egen hovedpine. Også, stack vs heap er ikke kun en præstationsovervejelse; det fortæller dig også meget om objekternes forventede levetid. Detaljer kan findes herfra. | OK, simpelthen og med korte ord betyder de bestilt og ikke bestilt ...! Stak: I stakgenstande kommer tingene oven på hinanden, hvilket betyder at det bliver hurtigere og mere effektivt at behandle! ... Så der er altid et indeks til at pege på den specifikke vare, også behandlingen bliver hurtigere, der er også forhold mellem varerne! ... Heap: Ingen ordre, behandlingen bliver langsommere, og værdierne bliver rodet sammen uden nogen bestemt rækkefølge eller indeks ... der er tilfældige, og der er ingen sammenhæng mellem dem ... så udførelse og brugstid kan variere ... Jeg opretter også billedet nedenfor for at vise, hvordan de kan se ud: | stack, heap og data for hver proces i virtuel hukommelse: | I 1980'erne forplantede UNIX sig som kaniner med store virksomheder, der rullede deres egne. Exxon havde en, ligesom dusinvis af mærker mistede i historien. Hvordan hukommelsen blev lagt, var efter de mange implementerers skøn. Et typisk C-program blev lagt fladt i hukommelsen med en mulighed for at øge ved at ændre brk () -værdien. Typisk var HEAP lige under denne brk-værdi og stigende brk øgede mængden af tilgængelig bunke. Den eneste STACK var typisk et område under HEAP, som var en hukommelseskanal der ikke indeholder noget af værdi indtil toppen af den næste faste hukommelsesblok. Denne næste blok var ofte CODE, som kunne overskrives af stack-data i en af de berømte hacks i sin æra. En typisk hukommelsesblok var BSS (en blok på nulværdier) som ved et uheld ikke blev nulstillet i en producents tilbud. En anden var DATA indeholdende initialiserede værdier, herunder strenge og tal. En tredje var CODE indeholdende CRT (C runtime), main, funktioner og biblioteker. Fremkomsten af virtuel hukommelse i UNIX ændrer mange af begrænsningerne. Der er ingen objektiv grund til, at disse blokke skal være sammenhængende, eller fast i størrelse, eller bestilt en bestemt måde nu. Naturligvis før UNIX var Multics, der ikke led af disse begrænsninger. Her er en skematisk oversigt, der viser et af hukommelseslayoutene i den æra. | Et par cent: Jeg tror, det vil være godt at tegne hukommelsen grafisk og mere enkel: Pile - viser hvor vokser stak og heap, processtakstørrelse har grænse, defineret i OS, trådstakstørrelsesgrænser efter parametre i tråd opretter API normalt. Heap begrænser normalt efter procesens maksimale virtuelle hukommelsesstørrelse, for eksempel for 32 bit 2-4 GB. Så enkel måde: procesbunke er generel for proces og alle tråde indeni og bruger til hukommelsesallokering i almindelige tilfælde med noget som malloc (). Stack er hurtig hukommelse til lagring af almindelige sagsfunktionsreturpegere og -variabler, behandlet som parametre i funktionsopkald, lokale funktionsvariabler. | Da nogle svar blev nitpikende, vil jeg bidrage med min mide. Overraskende har ingen nævnt, at flere (dvs. ikke er relateret til antallet af kørende tråde på OS-niveau) kaldestabler ikke kun findes på eksotiske sprog (PostScript) eller platforme (Intel Itanium), men også i fibre, grønne tråde og nogle implementeringer af coroutines. Fibre, grønne tråde og coroutines er på mange måder ens, hvilket fører til meget forvirring. Forskellen mellem fibre og grønne tråde er, at førstnævnte bruger kooperativ multitasking, mens sidstnævnte kan indeholde enten kooperativ eller præventiv (eller endda begge). For forskellen mellem fibre og coroutines, se her. Under alle omstændigheder er formålet med både fibre, grønne tråde og coroutines at have flere funktioner, der udføres samtidigt, men ikke parallelt (se dette SO-spørgsmål til sondring) inden for en enkelt OS-niveau-tråd, der overfører kontrol frem og tilbage fra hinanden på en organiseret måde. Når du bruger fibre, grønne tråde eller coroutines, har du normalt en separat stak pr. Funktion. (Teknisk set er ikke kun en stak, men en hel kontekst af udførelse pr. Funktion. Vigtigst er det, at CPU registrerer.) For hver tråd er der lige så mange stakke, som der kører funktioner, og tråden skifter mellem at udføre hver funktion i henhold til logikken i dit program. Når en funktion løber til slutningen, ødelægges dens stak. Så antallet og levetiden på stakke er dynamiske og bestemmes ikke af antallet af tråde på OS-niveau! Bemærk, at jeg sagde "har normalt en separat stak pr. Funktion". Der er både stablede og stakløse implementeringer af couroutines. De mest bemærkelsesværdige stablede C ++ - implementeringer er Boost.Coroutine og Microsoft PPL's async / wait. (C ++ 's genoptagelige funktioner (også kaldet "asynkronisering og afventning"), som blev foreslået til C ++ 17, vil sandsynligvis bruge stakløse coroutines.) Fibreforslag til C ++ - standardbiblioteket kommer. Der er også nogle tredjepartsbiblioteker. Grønne tråde er ekstremt populære på sprog som Python og Ruby. | Jeg har noget at dele, selvom de vigtigste punkter allerede er dækket. Stak Meget hurtig adgang. Gemt i RAM. Her indlæses funktionsopkald sammen med de lokale variabler og funktionsparametre, der er bestået. Plads frigøres automatisk, når programmet går ud af et omfang. Gemt i sekventiel hukommelse. Bunke Langsom adgang sammenlignet med Stack. Gemt i RAM. Her gemmes dynamisk oprettede variabler, som senere kræver frigørelse af den tildelte hukommelse efter brug. Opbevares overalt, hvor hukommelsestildeling sker, adgang til markøren altid. Interessant note: Skulle funktionsopkaldene være blevet lagret i bunke, ville det have resulteret i 2 rodede punkter: På grund af sekventiel opbevaring i stakken er udførelsen hurtigere. Opbevaring i dynger ville have resulteret i enormt tidsforbrug og dermed få hele programmet til at køre langsommere. Hvis funktioner blev gemt i bunke (rodet lager peget med markøren), ville der ikke have været nogen måde at vende tilbage til den kaldende adresse tilbage (som stakken giver på grund af sekventiel lagring i hukommelsen). | Wow! Så mange svar, og jeg tror ikke, at en af dem fik det rigtigt ... 1) Hvor og hvad er de (fysisk i en rigtig computers hukommelse)? Stakken er hukommelse, der begynder som den højeste hukommelsesadresse, der er tildelt dit programbillede, og derefter falder i værdi derfra. Det er forbeholdt kaldte funktionsparametre og til alle midlertidige variabler, der bruges i funktioner. Der er to dynger: offentlige og private. Den private bunke begynder på en 16-byte-grænse (til 64-bit-programmer) eller en 8-byte-grænse (til 32-bit-programmer) efter den sidste byte med kode i dit program og øges derefter iværdi derfra. Det kaldes også standardbunken. Hvis den private bunke bliver for stor, overlapper den stabelområdet, ligesom stakken overlapper bunken, hvis den bliver for stor. Fordi stakken starter ved en højere adresse og arbejder sig ned til lavere adresse, kan du med ordentlig hacking gøre stakken så stor, at den overskrider det private bunkeområde og overlapper kodeområdet. Tricket er derefter at overlappe nok af kodeområdet, så du kan tilslutte koden. Det er lidt vanskeligt at gøre, og du risikerer et programnedbrud, men det er let og meget effektivt. Den offentlige bunke ligger i sin egen hukommelsesplads uden for dit program billedrum. Det er denne hukommelse, der sippes ud på harddisken, hvis hukommelsesressourcerne bliver knappe. 2) I hvilket omfang styres de af OS eller sprogkørselstid? Stakken styres af programmøren, den private bunke styres af operativsystemet, og den offentlige bunke styres ikke af nogen, fordi det er en OS-tjeneste - du fremsætter anmodninger, og de tildeles eller nægtes enten. 2b) Hvad er deres anvendelsesområde? De er alle globale for programmet, men deres indhold kan være privat, offentligt eller globalt. 2c) Hvad bestemmer størrelsen på hver af dem? Størrelsen på stakken og den private bunke bestemmes af dine compiler runtime-indstillinger. Den offentlige bunke initialiseres ved kørsel ved hjælp af en størrelsesparameter. 2d) Hvad gør en hurtigere? De er ikke designet til at være hurtige, de er designet til at være nyttige. Hvordan programmøren bruger dem bestemmer, om de er "hurtige" eller "langsomme" REF: https://norasandler.com/2019/02/18/Write-a-Compiler-10.html https://docs.microsoft.com/en-us/windows/desktop/api/heapapi/nf-heapapi-getprocessheap https://docs.microsoft.com/en-us/windows/desktop/api/heapapi/nf-heapapi-heapcreate | Mange svar er korrekte som begreber, men vi skal bemærke, at hardwaren (dvs. mikroprocessor) har brug for en stak for at tillade opkald til underrutiner (CALL på samlingssprog ..). (OOP fyre kalder det metoder) På stakken gemmer du returadresser og kalder → push / ret → pop styres direkte i hardware. Du kan bruge stakken til at overføre parametre .. selvom den er langsommere end at bruge registre (ville en mikroprocessorguru sige eller en god BIOS-bog fra 1980'erne ...) Uden stak kan ingen mikroprocessor arbejde. (vi kan ikke forestille os et program, selv på forsamlingssprog uden underrutiner / funktioner) Uden bunken kan det. (Et samlingssprogprogram kan arbejde uden, da bunken er et OS-koncept, som malloc, det er et OS / Lib-opkald. Stakanvendelsen er hurtigere, da: Er hardware, og endda push / pop er meget effektive. malloc kræver at gå ind i kernetilstand, bruge lås / semafor (eller andre synkroniseringsprimitiver) til at udføre en kode og styre nogle strukturer, der er nødvendige for at holde styr på allokering. | Heap er et område med dynamisk allokeret hukommelse, der administreres automatisk af operativsystemet eller hukommelsesadministratorbiblioteket. Du kan tildele en blok til enhver tid og frigøre den til enhver tid. Heapallokering kræver, at du opretholder en fuld oversigt over, hvilken hukommelse der er tildelt, og hvad der ikke er, samt noget vedligeholdelsesarbejde for at reducere fragmentering, finde sammenhængende hukommelsessegmenter, der er store nok til at passe til den ønskede størrelse osv. Hukommelse kan tildeles på et hvilket som helst tidspunkt, hvilket giver ledig plads. Efterhånden som dyngen vokser, tildeles nye blokke ofte fra lavere adresser til højere adresser. Således kan du tænke på bunken som en bunke med hukommelsesblokke, der vokser i størrelse, når hukommelsen tildeles. Hvis bunken er for lille til en allokering, kan størrelsen ofte øges ved at erhverve mere hukommelse fra det underliggende operativsystem. Hukommelse allokeret fra bunken forbliver allokeret, indtil et af følgende sker: Hukommelsen frigøres Programmet afsluttes Stak: Gemt i computerens RAM ligesom bunken. Variabler, der er oprettet på stakken, kommer uden for rækkevidden og deles automatisk. Meget hurtigere at allokere i forhold til variabler på bunken. Gemmer lokale data, returadresser, der bruges til parameteroverføring. Kan have et steapeloverløb, når der bruges for meget af stakken (for det meste fra uendelig eller for dyb rekursion, meget store allokeringer). Du ville bruge stakken, hvis du ved nøjagtigt, hvor meget data du har brug for alloker inden kompileringstid, og den er ikke for stor. Normalt har en maksimal størrelse allerede bestemt, når dit program starter. Bunke: Gemt i computerens RAM ligesom stakken. I C ++ skal variabler på bunken destrueres manuelt og aldrig falder uden for anvendelsesområdet. Dataene frigøres med sletning, sletning [] eller gratis. Langsommere at allokere i forhold til variabler på stakken. Anvendes efter behov til at allokere en datablok til brug af programmet. Kan have fragmentering, når der er mange tildelinger og deallokationer. I C ++ eller C vil data oprettet på bunken blive peget på af markører og tildeles med henholdsvis nyt eller malloc. Kan have allokeringsfejl, hvis der anmodes om for stor buffer tildeles. Duville bruge bunken, hvis du ikke ved nøjagtigt, hvor mange data du har har brug for på kørselstid, eller hvis du har brug for at allokere en masse data. Ansvarlig for hukommelseslækage. | Stakken er i det væsentlige en let tilgængelig hukommelse, der simpelthen administrerer dens emner som en - godt - stak. Kun emner, hvor størrelsen er kendt på forhånd, kan gå på stakken. Dette er tilfældet for tal, strenge, booleanske. Bunken er en hukommelse for emner, som du ikke kan forudbestemme nøjagtig størrelse og struktur. Da objekter og arrays kan muteres og ændring ved kørsel, er de nødt til at gå ind i bunken. Kilde: Academind | CPU-stack og heap er fysisk relateret til, hvordan CPU og registre fungerer med hukommelse, hvordan maskinsamlingssprog fungerer, ikke sprog på højt niveau selv, selvom disse sprog kan bestemme små ting. Alle moderne CPU'er arbejder med den "samme" mikroprocessor teori: de er alle baseret på det, der kaldes "registre", og nogle er beregnet til "stack" for at opnå ydeevne. Alle CPU'er har stakregistre siden starten, og de havde altid været her, måde at tale på, som jeg ved. Samlingssprog er de samme siden starten, på trods af variationer ... op til Microsoft og dets mellemliggende sprog (IL), der ændrede paradigmet til at have et OO-sprog til samling af virtuel maskine. Så vi kan have nogle CLI / CIL CPU'er i fremtiden (et projekt af MS). CPU'er har stakregistre for at fremskynde adgangen til hukommelser, men de er begrænsede sammenlignet med brugen af andre registre for at få fuld adgang til al ledig hukommelse til processen. Derfor talte vi om stak- og dyngetildelinger. Sammenfattende og generelt er bunken hudge og langsom og er til "globale" forekomster og objekter, da stakken er lille og hurtig og til "lokale" variabler og referencer (skjulte pekere at glemme at administrere dem). Så når vi bruger det nye nøgleord i en metode, oprettes referencen (en int) i stakken, men objektet og alt dets indhold (værdityper såvel som objekter) oprettes i bunken, hvis jeg husker det. Men lokale elementære værdityper og arrays oprettes i stakken. Forskellen i hukommelsesadgang er på cellerne, der henviser til niveau: adressering af bunken, procesens samlede hukommelse, kræver mere kompleksitet med hensyn til håndtering af CPU-registre end stakken, der er "mere" lokalt med hensyn til adressering, fordi CPU-stakken register bruges som basisadresse, hvis jeg husker det. Det er grunden til, at når vi har meget lange eller uendelige tilbagekaldelsesopkald eller sløjfer, fik vi stackoverløb hurtigt uden at fryse systemet på moderne computere ... C # Heap (ing) Vs Stack (ing) I .NET Stack vs Heap: Kend forskellen Statisk klassehukommelsestildeling, hvor den er gemt C # Hvad og hvor er stakken og bunken? https://en.wikipedia.org/wiki/Memory_management https://en.wikipedia.org/wiki/Stack_register Samlingssprogressourcer: Samlingsprogrammeringsvejledning Intel® 64 og IA-32 Architectures Software Developer Manuals | Tak for en rigtig god diskussion, men som en rigtig noob spekulerer jeg på, hvor instruktionerne opbevares? I BEGINNELSEN besluttede forskere mellem to arkitekturer (von NEUMANN, hvor alt betragtes som DATA og HARVARD, hvor et hukommelsesområde var forbeholdt instruktioner og et andet til data). I sidste ende gik vi med von Neumann-designet, og nu betragtes alt som 'det samme'. Dette gjorde det svært for mig, da jeg lærte at samle https://www.cs.virginia.edu/~evans/cs216/guides/x86.html fordi de taler om registre og stakmarkører. Alt ovenfor taler om DATA. Mit gæt er, at da en instruktion er en defineret ting med et specifikt hukommelsesfodaftryk, vil den gå på stakken, og så er alle 'disse' registre, der diskuteres i samlingen, på stakken. Selvfølgelig kom der objektorienteret programmering med instruktioner og data, der kom ind i en struktur, der var dynamisk, så nu skulle instruktionerne også holdes på bunken? | Meget aktivt spørgsmål. Optjen 10 omdømme for at besvare dette spørgsmål. Omdømmekravet hjælper med at beskytte dette spørgsmål mod spam og ikke-svar-aktivitet. Er det ikke det svar, du leder efter? Gennemse andre spørgsmål mærket hukommelsesadministrationsstabel sprog-agnostisk bunke dynamisk-hukommelsesallokering eller stil dit eget spørgsmål.